#ifndef _EXTENSION_BASE_CLASS_H_
#define _EXTENSION_BASE_CLASS_H_
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <list>
#include <string.h>

#include <mutex>

template<typename t_data>
class base_memory_data_unit
{
public:
    explicit base_memory_data_unit( const unsigned int ui_len )
        : mp_data( new t_data[ui_len]), mui_len(ui_len), mui_usedlen(0), mp_front(NULL), mp_next(NULL){

    }

    ~base_memory_data_unit()
    {
        if( mp_data ){
            delete []mp_data;
            mp_data = NULL;
        }
        mp_front = NULL;
        mp_next = NULL;
    }

    t_data *get_data()
    {
        return mp_data;
    }

    unsigned int get_len()
    {
        return mui_len;
    }

    t_data *mp_data;
    unsigned int mui_len;
    unsigned int mui_usedlen;
    base_memory_data_unit<t_data> *mp_front;
    base_memory_data_unit<t_data> *mp_next;
};

template<typename t_data>
class base_memory_pool
{
public:
    base_memory_pool()
        : mp_head(NULL), mp_tail(NULL), mui_size(0), mui_cursize(0), mui_limitsize(0){
    }

    virtual ~base_memory_pool()
    {
        cache_pool_clear();
    }

    bool cache_pool_init( const unsigned int ui_limitsize, const unsigned int ui_initsize, unsigned int ui_buffsize )
    {
        mo_lock.lock();
        mui_limitsize = ui_limitsize;
        unsigned int ui_del = 0;
        for( unsigned int ui_index = 0; ui_index < ui_initsize; ++ui_index ){
             base_memory_data_unit<t_data> *p_unit = new base_memory_data_unit<t_data>(ui_buffsize);
             if( p_unit != NULL ){
                 if( p_unit->get_data() != NULL ){
                     cache_pool_push_back( p_unit );
                 } else {
                     delete p_unit;
                     ui_del++;
                 }
             } else {
                 ui_del++;
             }
            //cache_pool_push_back( new base_memory_data_unit<Data>(ui_buffsize) );
        }

        mui_init_buffsize = ui_buffsize;
        mui_size = ui_initsize - ui_del;
        mui_cursize = ui_initsize - ui_del;
        mo_lock.unlock();
        return true;
    }

    base_memory_data_unit<t_data> *cache_pool_get_data( const unsigned int ui_needlen )
    {
        mo_lock.lock();
        base_memory_data_unit<t_data> *p_tmp = mp_head;
        while( p_tmp ){
            if( ui_needlen <= p_tmp->get_len() ){
                if( p_tmp == mp_head ){
                    mp_head = p_tmp->mp_next;
                    if( mp_head ){
                        mp_head->mp_front = NULL;
                    } else {
                        mp_tail = NULL;
                    }
                } else {
                    p_tmp->mp_front->mp_next = p_tmp->mp_next;
                    if( p_tmp->mp_next ){
                        p_tmp->mp_next->mp_front = p_tmp->mp_front;
                    }
                    if( p_tmp == mp_tail ){
                        mp_tail = p_tmp->mp_front;
                    }
                }

                p_tmp->mp_front = NULL;
                p_tmp->mp_next = NULL;
                mui_cursize--;
                break;
            }

            p_tmp = p_tmp->mp_next;
        }

        if( !p_tmp ){
            if( mui_size < mui_limitsize ){
                if( ui_needlen < mui_init_buffsize ){
                    base_memory_data_unit<t_data> *p_new = new base_memory_data_unit<t_data>( mui_init_buffsize );
                    if( p_new != NULL ){
                        if( p_new->get_data() != NULL ){
                            p_tmp = p_new;
                            mui_size++;
                        } else {
                            delete p_new;
                            p_new = NULL;
                        }
                    }
                } else {
                    base_memory_data_unit<t_data> *p_new = new base_memory_data_unit<t_data>( ui_needlen );
                    if( p_new != NULL ){
                        if( p_new->get_data() != NULL ){
                            p_tmp = p_new;
                            mui_size++;
                        } else {
                            delete p_new;
                        }
                    }
                }                
            } else {
                mo_lock.unlock();
                return NULL;
            }
        }

        mo_lock.unlock();

        if( p_tmp ){
            p_tmp->mui_usedlen = ui_needlen;
        }
        return p_tmp;
    }

    void cache_pool_return( base_memory_data_unit<t_data> *punit )
    {
        if( punit != NULL ){
            mo_lock.lock();
            cache_pool_push_back( punit );
            mo_lock.unlock();
        }
    }
private:
    void cache_pool_push_back( base_memory_data_unit<t_data> *punit )
    {
        if( mp_tail ){
            mp_tail->mp_next = punit;
            punit->mp_front = mp_tail;
        } else {
            mp_head = punit;
        }

        mp_tail = punit;
        mui_cursize++;
    }

    void cache_pool_clear()
    {
        mo_lock.lock();
        base_memory_data_unit<t_data> *p_tmp = mp_head;
        while( p_tmp ){
            base_memory_data_unit<t_data> *p_next = p_tmp->mp_next;
            delete p_tmp;
            p_tmp = p_next;
        }

        mp_head = NULL;
        mp_tail = NULL;
        mui_size = 0;
        mui_cursize = 0;
        mui_limitsize = 0;
        mo_lock.unlock();
    }

private:
    std::mutex mo_lock;
    base_memory_data_unit<t_data> *mp_head;
    base_memory_data_unit<t_data> *mp_tail;
    unsigned int  mui_size;
    unsigned int  mui_cursize;
    unsigned int  mui_limitsize;
    unsigned int  mui_init_buffsize;
};

template <typename RWLOCK, bool b_reader = true>
class base_auto_rw_lock
{
public:
    explicit base_auto_rw_lock(const RWLOCK* p) : m_pLock(const_cast< RWLOCK*>(p))
    {
        if (b_reader){
            pthread_rwlock_rdlock( m_pLock );
        } else {
            pthread_rwlock_wrlock( m_pLock );
        }
    }
    ~base_auto_rw_lock()
    {
        pthread_rwlock_unlock( m_pLock );
    }
private:
    base_auto_rw_lock(const base_auto_rw_lock&);
    base_auto_rw_lock& operator=(const base_auto_rw_lock&);
    RWLOCK* m_pLock;
};

template <typename T>
class singleton_locker_factory : public T
{
public:
    static T* Instance()
    {
        if (m_pInstance == NULL)
        {
            std::lock_guard<std::mutex> auto_lock(m_Lock);
            if (m_pInstance == NULL)
            {
                m_pInstance = new T;
            }
        }
        return m_pInstance;
    }

    static void Uninstance()
    {
        if (m_pInstance != NULL)
        {
            std::lock_guard<std::mutex> auto_lock(m_Lock);
            if (m_pInstance != NULL)
            {
                delete m_pInstance;
                m_pInstance = NULL;
            }
        }
    }
private:
    singleton_locker_factory();
    ~singleton_locker_factory();

    singleton_locker_factory(const singleton_locker_factory& singletonhandler);
    singleton_locker_factory& operator=(const singleton_locker_factory& singletonhandler);

    static T* m_pInstance;
    static std::mutex m_Lock;
};

template <typename T>
T* singleton_locker_factory<T>::m_pInstance = NULL;

template<typename T>
std::mutex singleton_locker_factory<T>::m_Lock;

#endif
